// DllImport - A C#-like DLL Wrapper
// written by oldrev (wstring#gmail.com)
// License: BSD

module dayudict.util.dll;

import std.traits;
import std.string;
import std.utf;

import std.c.windows.windows;


extern(Windows)
{
	HMODULE LoadLibraryW(LPCWSTR libPath);
}


private static class ModuleManager
{
	private static HMODULE	[char[]]	m_modules;

	private this()
	{
	}

	static public ~this()
	{
		foreach(h; m_modules)
		{
			FreeLibrary(h);
		}
	}

	private static HMODULE registerModule(char[] name)
	{
		char[] lname = tolower(name);
		HMODULE h = LoadLibraryW(toUTF16z(lname));
		if(h is null)
			throw new Exception("Failed to load DLL: " ~ name);
		m_modules[lname] = h;
		return h;
	}

	public static HMODULE getHandle(char[] name)
	{
		return m_modules[name];
	}

	public static ProcType getSymbol(ProcType)(char[] moduleName, char[] procName)
	{
		HMODULE handle = null;
		if(moduleName in m_modules)
			handle = m_modules[moduleName];		
		else
			handle = registerModule(moduleName);

		assert(handle !is null);
		ProcType proc = cast(ProcType)GetProcAddress(handle, toStringz(procName));
		if(proc is null)
			throw new Exception("Cannot to get the address of " ~ procName);
		return proc;
	}
}

struct DllImport(char[] ModuleName, char[] ProcName, FT)
{
   	extern(Windows) alias ReturnType!(FT) 
        function(ParameterTypeTuple!(FT))     FunctionType;
	alias DllImport!(ModuleName, ProcName, FT) SelfType;

	// I really hate CTFE!
	//FIXME:
	private FunctionType m_funcPtr = null;		

	public ReturnType!(FunctionType) opCall(ParameterTypeTuple!(FunctionType) args)
	{
		if(m_funcPtr is null)
			m_funcPtr = ModuleManager.getSymbol!(FunctionType)(ModuleName, ProcName);		
		return m_funcPtr(args);
	}
}

 
/*
void main()
{
	DllImport!("user32.dll", "MessageBoxA", 
			int function(HWND hWnd, LPCSTR lpText, LPCSTR lpCaption, UINT uType)) MessageBox;

	MessageBox(null, "Text", "Title", MB_OK);
}
*/
